home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus Extra 1997 #1
/
Amiga Plus Extra 1997 #1.iso
/
programme
/
tools
/
leoutils
/
guidecat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-25
|
28KB
|
1,048 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LeoLib.h"
#define VERSION "1.11"
#if !defined _AMIGA && !defined AMIGA
typedef short BOOL;
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* The following are for ANSI C compilers with bad stdio.h */
#if !defined _IOFBF
#define _IOFBF 0
#endif
static void SetStupidTerminal(BOOL Stupid);
static void Bold(FILE *OutFile);
static void Italics(FILE *OutFile);
static void Reverse(FILE *OutFile);
static void Underline(FILE *OutFile);
static void BoldOff(FILE *OutFile);
static void ItalicsOff(FILE *OutFile);
static void ReverseOff(FILE *OutFile);
static void UnderlineOff(FILE *OutFile);
static void FGColor(FILE *OutFile, int Color);
static void BGColor(FILE *OutFile, int Color);
static void Normal(FILE *OutFile);
static void StoreTextMode(void);
static void RestoreTextMode(FILE *OutFile);
static void ReadAGFile(FILE *InFile);
static void WordAddChar(char NewC);
static void WordSend(void);
static void SkipSpaces(FILE *InFile);
static void SkipUntilSpace(FILE *InFile);
static void SkipToEOL(FILE *InFile);
static int ReadToUpper(FILE *InFile, char *string, int n);
static void PutInit(FILE *OutFile);
static void PutWord(char *Str);
static void PutEOL(void);
static void PutEnd(void);
static void PutTab(void);
static void PutSpace(void);
static void PutSetWidth(int Width);
static void PutSetWrap(void);
static void PutPurgeSpace(void);
static void NodeInit(void);
static int NodeNumber(char *Str);
static void NodeEnd(void);
static int AGParseCommand(char *Command, FILE *InFile);
static int AGArgs(void);
static char *AGArg(int Arg);
static char *AGArgU(int Arg);
#if defined _AMIGA || defined AMIGA
static char *Ver = "$VER:GuideCat " VERSION
#if defined __SASC
" " __AMIGADATE__ " ©1994-6 Leopold-Soft"
#endif
;
#endif
static BOOL NodeItalics = TRUE, NodeBold = TRUE, NodeReverse = TRUE,
LinkItalics = FALSE, LinkBold = FALSE, LinkReverse = TRUE,
IndexNumbering = TRUE, fileArguments = FALSE, Plain = FALSE,
Brackets = FALSE;
static int NodeColor = 1, LinkColor = 1, ColColor = 2;
static BOOL ColReverse = FALSE;
static void *InBuff = NULL;
/***********************************\
* *
* Main - command line parser *
* *
\***********************************/
int main(int argc, char **argv) {
static int CurrArg = 0;
static FILE *InFile;
static char *ColumnsStr;
static int Columns = 0;
if ((ColumnsStr = getenv("COLUMNS")) && (Columns = atoi(ColumnsStr)))
PutSetWidth(Columns);
while(++CurrArg < argc) {
/* NODE OPTIONS */
if (!strcmp(argv[CurrArg],"-nI")) {
NodeItalics = TRUE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-ni")) {
NodeItalics = FALSE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-nB")) {
NodeBold = TRUE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-nb")) {
NodeBold = FALSE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-nR")) {
NodeReverse = TRUE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-nr")) {
NodeReverse = FALSE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-nC")) {
if (argc > CurrArg+1) {
NodeColor = atoi(argv[++CurrArg]);
if (NodeColor < 1 || NodeColor > 7) {
NodeColor = 1;
CurrArg--;
}
}
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-nc")) {
NodeColor = 1;
Plain = FALSE;
/* LINK OPTIONS */
} else if (!strcmp(argv[CurrArg],"-lI")) {
LinkItalics = TRUE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-li")) {
LinkItalics = FALSE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-lB")) {
LinkBold = TRUE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-lb")) {
LinkBold = FALSE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-lR")) {
LinkReverse = TRUE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-lr")) {
LinkReverse = FALSE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-lC")) {
if (argc > CurrArg+1) {
LinkColor = atoi(argv[++CurrArg]);
if (LinkColor < 1 || LinkColor > 7) {
LinkColor = 1;
CurrArg--;
}
}
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-lc")) {
LinkColor = 1;
Plain = FALSE;
/* COLOR OPTIONS */
} else if (!strcmp(argv[CurrArg],"-cR")) {
ColReverse = TRUE;
ColColor = 1;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-cr")) {
ColReverse = FALSE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-cC")) {
if (argc > CurrArg+1) {
ColColor = atoi(argv[++CurrArg]);
if (ColColor < 1 || ColColor > 7) {
ColColor = 1;
CurrArg--;
}
}
ColReverse = FALSE;
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-cc")) {
ColColor = 1;
/* OTHER OPTIONS */
} else if (!strcmp(argv[CurrArg],"-I")) {
IndexNumbering = TRUE;
} else if (!strcmp(argv[CurrArg],"-i")) {
IndexNumbering = FALSE;
} else if (!strcmp(argv[CurrArg],"-S")) {
SetStupidTerminal(TRUE);
} else if (!strcmp(argv[CurrArg],"-s")) {
SetStupidTerminal(FALSE);
} else if (!strcmp(argv[CurrArg],"-B")) {
Brackets = TRUE;
} else if (!strcmp(argv[CurrArg],"-b")) {
Brackets = FALSE;
} else if (!strcmp(argv[CurrArg],"-P")) {
Plain = TRUE;
} else if (!strcmp(argv[CurrArg],"-p")) {
Plain = FALSE;
} else if (!strcmp(argv[CurrArg],"-A")) {
Brackets = TRUE;
} else if (!strcmp(argv[CurrArg],"-a")) {
Brackets = FALSE;
} else if (!strcmp(argv[CurrArg],"-w") || !strcmp(argv[CurrArg],"-W")) {
if (argc > CurrArg+1) {
static int Tmp;
Tmp = atoi(argv[++CurrArg]);
if (Tmp == 0) {
CurrArg--;
} else {
PutSetWidth(Tmp);
}
}
} else if (!strcmp(argv[CurrArg],"-d0")) {
NodeItalics = TRUE; NodeBold = TRUE; NodeReverse = TRUE;
LinkItalics = FALSE; LinkBold = FALSE; LinkReverse = TRUE;
IndexNumbering = TRUE; fileArguments = FALSE; Plain = FALSE;
Brackets = FALSE; NodeColor = 1; LinkColor = 1;
ColReverse = FALSE; ColColor = 2;
SetStupidTerminal(TRUE);
} else if (!strcmp(argv[CurrArg],"-d1")) {
NodeItalics = FALSE; NodeBold = TRUE; NodeReverse = FALSE;
LinkItalics = FALSE; LinkBold = TRUE; LinkReverse = FALSE;
IndexNumbering = TRUE; fileArguments = FALSE; Plain = FALSE;
Brackets = FALSE; NodeColor = 3; LinkColor = 3;
ColReverse = FALSE; ColColor = 2;
SetStupidTerminal(FALSE);
} else if (!strcmp(argv[CurrArg],"-d2")) {
NodeItalics = FALSE; NodeBold = FALSE; NodeReverse = FALSE;
LinkItalics = FALSE; LinkBold = FALSE; LinkReverse = FALSE;
IndexNumbering = TRUE; fileArguments = FALSE; Plain = TRUE;
Brackets = TRUE; NodeColor = 1; LinkColor = 1;
ColReverse = FALSE; ColColor = 1;
SetStupidTerminal(TRUE);
} else if (!strcmp(argv[CurrArg],"-h") || !strcmp(argv[CurrArg],"?")) {
printf("\nGuideCat " VERSION " ©1994-6 Henrik Herranen\n\n"
"Usage: %s [?|-h] | [-n[I|i]] | [-n[B|b]] | [-n[R|r]] | [-l[I|i]] | [-l[B|b]] | [-l[R|r]] | [filename]\n\n"
"-h or ? Show this help page.\n"
" def: 0 1 2\n"
"-nI or -ni Turns Italics on/off in node headers on off off\n"
"-nB or -nb Turns Bold on/off in node headers on off off\n"
"-nR or -nr Turns Reverse on/off in node headers on off off\n"
"-nC x or -nc Sets color on/off in node headers off 3 off\n"
"-lI or -li Turns Italics on/off in links off off off\n"
"-lB or -lb Turns Bold on/off in links off off off\n"
"-lR or -lr Turns Reverse on/off in links on off off\n"
"-lC x or -lc Sets color on/off in links off 3 off\n"
"-cR or -cr Turns Reverse on/off for colors off off off\n"
"-cC x or -cc Sets colors on+hilite/off for colors 2 2 off\n"
"-I or -i Switches node index numbering on/off on on on\n"
"-S or -s Switches stupid terminal mode on/off on off on\n"
"-A or -a Brackets around nodes+links on/off off off on\n"
"-P pr -p plain output on/off off off on\n"
"-w x (x>=20) Set display width if WORDWRAP used 78 78 78\n"
"-d0 .. -d2 Use defaults 0..2\n"
"filename the named file will be read as an AmigaGuide file.\n\n"
,argv[0]);
fileArguments = TRUE;
} else {
if (InFile = fopen(argv[CurrArg], "ra")) {
if (!InBuff) InBuff = malloc(16384);
if (InBuff) setvbuf(InFile, InBuff, _IOFBF, (size_t) 16384);
ReadAGFile(InFile);
fclose(InFile);
} else {
fprintf(stderr,"%s: *** ERROR: Couldn't open file '%s'!\n", argv[0], argv[CurrArg]);
}
fileArguments = TRUE;
}
}
if (!fileArguments) {
fprintf(stderr,"%s: Reading from standard input. Press "
#if defined _AMIGA || defined AMIGA
"ctrl-\\"
#else
"ctrl-D"
#endif
" to stop if running interactively.\n", argv[0]);
ReadAGFile(stdin);
}
return EXIT_SUCCESS;
}
/***********************************\
* *
* Text formatting functions *
* *
\***********************************/
struct TextMode {
BOOL Bold, Italics, Reverse, Underline;
int FGColor, BGColor;
};
static struct TextMode CurrTextMode = {FALSE, FALSE, FALSE, FALSE, 1, 0}, StoredTextMode;
static BOOL StupidTerminal = TRUE;
static void SetStupidTerminal(BOOL Stupid) {
StupidTerminal = Stupid;
}
static void Bold(FILE *OutFile) {
if (!CurrTextMode.Bold) {
fprintf(OutFile,"\033[1m");
CurrTextMode.Bold = TRUE;
}
}
static void Italics(FILE *OutFile) {
if (!CurrTextMode.Italics) {
fprintf(OutFile,"\033[3m");
CurrTextMode.Italics = TRUE;
}
}
static void Reverse(FILE *OutFile) {
if (!CurrTextMode.Reverse) {
fprintf(OutFile,"\033[7m");
CurrTextMode.Reverse = TRUE;
}
}
static void Underline(FILE *OutFile) {
if (!CurrTextMode.Underline) {
fprintf(OutFile,"\033[4m");
CurrTextMode.Underline = TRUE;
}
}
/* The following function is only for internal use */
/* -> no prototype provided */
static void SetTextModeOnStupidTerminal(FILE *OutFile) {
struct TextMode TmpTextMode = CurrTextMode;
Normal(OutFile);
if (TmpTextMode.Bold) Bold(OutFile);
if (TmpTextMode.Italics) Italics(OutFile);
if (TmpTextMode.Reverse) Reverse(OutFile);
if (TmpTextMode.Underline) Underline(OutFile);
if (TmpTextMode.FGColor != 1) FGColor(OutFile, StoredTextMode.FGColor);
if (TmpTextMode.BGColor != 0) BGColor(OutFile, StoredTextMode.BGColor);
}
static void BoldOff(FILE *OutFile) {
if (CurrTextMode.Bold) {
CurrTextMode.Bold = FALSE;
if (StupidTerminal) SetTextModeOnStupidTerminal(OutFile);
else fprintf(OutFile,"\033[22m");
}
}
static void ItalicsOff(FILE *OutFile) {
if (CurrTextMode.Italics) {
CurrTextMode.Italics = FALSE;
if (StupidTerminal) SetTextModeOnStupidTerminal(OutFile);
else fprintf(OutFile,"\033[23m");
}
}
static void ReverseOff(FILE *OutFile) {
if (CurrTextMode.Reverse) {
CurrTextMode.Reverse = FALSE;
if (StupidTerminal) SetTextModeOnStupidTerminal(OutFile);
else fprintf(OutFile,"\033[27m");
}
}
static void UnderlineOff(FILE *OutFile) {
if (CurrTextMode.Underline) {
CurrTextMode.Underline = FALSE;
if (StupidTerminal) SetTextModeOnStupidTerminal(OutFile);
else fprintf(OutFile,"\033[24m");
}
}
static void FGColor(FILE *OutFile, int Color) {
fprintf(OutFile,"\033[3%dm", Color & 7);
CurrTextMode.FGColor = Color & 7;
}
static void BGColor(FILE *OutFile, int Color) {
fprintf(OutFile,"\033[4%dm", Color & 7);
CurrTextMode.BGColor = Color & 7;
}
static void Normal(FILE *OutFile) {
CurrTextMode.Bold = FALSE;
CurrTextMode.Italics = FALSE;
CurrTextMode.Reverse = FALSE;
CurrTextMode.Underline = FALSE;
CurrTextMode.FGColor = 1;
CurrTextMode.BGColor = 0;
fprintf(OutFile,"\033[0m");
}
static void StoreTextMode(void) {
StoredTextMode = CurrTextMode;
}
static void RestoreTextMode(FILE *OutFile) {
if (CurrTextMode.Bold != StoredTextMode.Bold ||
CurrTextMode.Italics != StoredTextMode.Italics ||
CurrTextMode.Reverse != StoredTextMode.Reverse ||
CurrTextMode.Underline != StoredTextMode.Underline ||
CurrTextMode.FGColor != StoredTextMode.FGColor ||
CurrTextMode.BGColor != StoredTextMode.BGColor) {
if (CurrTextMode.Bold || CurrTextMode.Italics ||
CurrTextMode.Reverse || CurrTextMode.Underline ||
CurrTextMode.FGColor != 1 || CurrTextMode.BGColor != 0) {
Normal(OutFile);
if (StoredTextMode.Bold) Bold(OutFile);
if (StoredTextMode.Italics) Italics(OutFile);
if (StoredTextMode.Reverse) Reverse(OutFile);
if (StoredTextMode.Underline) Underline(OutFile);
if (StoredTextMode.FGColor != 1) FGColor(OutFile, StoredTextMode.FGColor);
if (StoredTextMode.BGColor != 0) BGColor(OutFile, StoredTextMode.BGColor);
}
}
}
static int ReadToUpper(FILE *InFile, char *string, int n) {
static int i, InC;
for (i=0; i<n; i++) {
if ((InC = fgetc(InFile)) != -1) {
*(string++) = ToUpper(InC);
} else {
return i;
}
}
return n;
}
static void SkipSpaces(FILE *InFile) {
static int InC;
while (IsSpace(InC = fgetc(InFile)));
if (InC != -1) ungetc(InC, InFile);
}
static void SkipUntilSpace(FILE *InFile) {
static int InC;
while (!IsSpace(InC = fgetc(InFile)) && InC != -1);
if (InC != -1) ungetc(InC, InFile);
}
static void SkipToEOL(FILE *InFile) {
static int InC;
while ((InC = fgetc(InFile)) != -1 && InC != '\n');
if (InC != -1) ungetc(InC, InFile);
}
/***********************************\
* *
* The AmigaGuide parser *
* *
\***********************************/
static void ReadAGFile(FILE *InFile) {
static char TmpStr[81], TmpStr2[81];
static int InC, i;
BOOL LastNewLine = TRUE, InsideNode = FALSE, Command = FALSE;
ReadToUpper(InFile,TmpStr,10);
if (memcmp(TmpStr,"@DATABASE ",10)) {
fprintf(stderr," *** ERROR: Not a valid AmigaGuide file!\n");
return;
}
printf("\nDATABASE: ");
while ((InC = fgetc(InFile)) != '\n') {
if (InC == -1) {
fprintf(stderr," *** ERROR: Unexpected end of file!\n");
return;
} else {
fputc(InC, stdout);
}
}
fputc('\n', stdout);
PutInit(stdout);
NodeInit();
while (!feof(InFile)) {
InC = fgetc(InFile);
if (InC == '@') { /* The command character @ */
InC = fgetc(InFile);
if (LastNewLine && InC != '{') { /* If a command line */
ungetc(InC, InFile);
AGParseCommand(NULL, InFile);
if (feof(InFile)) return;
if (!strcmp(AGArgU(0), "NODE")) { /* recognize commands */
if (!InsideNode) {
InsideNode = TRUE;
Normal(stdout);
printf("\n\n\n%sNODE: ", (Brackets ? "[" : ""));
if (!Plain) {
if (NodeItalics) Italics(stdout);
if (NodeBold) Bold(stdout);
if (NodeReverse) Reverse(stdout);
if (NodeColor != 1) FGColor(stdout, NodeColor);
}
if (IndexNumbering) printf("(%d) ", NodeNumber(AGArgU(1)));
if (AGArgs() > 2) {
printf("%s", AGArg(2));
} else {
printf("*** Internal name: %s ***", AGArgU(1));
}
if ((NodeItalics || NodeBold || NodeReverse || NodeColor != 1)
&& !Plain) Normal(stdout);
printf("%s\n", (Brackets ? "]" : ""));
}
} else if (!strcmp(AGArgU(0), "ENDNODE")) {
if (InsideNode) {
InsideNode = FALSE;
}
} else if (!strcmp(AGArgU(0), "WORDWRAP")) {
PutSetWrap();
} /* End of recognized commands */
InC = '\n';
Command = TRUE;
} else if (InC == '{') { /* If link or inline command */
ungetc(InC, InFile);
AGParseCommand(NULL, InFile);
if (AGArgs() >= 3 && !strcmp(AGArgU(1), "LINK")) { /* If link */
WordSend();
if (!Plain) {
StoreTextMode();
Normal(stdout);
if (LinkItalics) Italics(stdout);
if (LinkBold) Bold(stdout);
if (LinkReverse) Reverse(stdout);
if (LinkColor != 1) FGColor(stdout, LinkColor);
}
strncpy(TmpStr, AGArg(0), 60);
if (IndexNumbering) {
sprintf(TmpStr2, "(%d) %s", NodeNumber(AGArgU(2)), TmpStr);
strcpy(TmpStr, TmpStr2);
}
if (Brackets) {
sprintf(TmpStr2, "[%s]", TmpStr);
strcpy(TmpStr, TmpStr2);
}
PutWord(TmpStr);
if (!Plain) RestoreTextMode(stdout);
InC = '}';
Command = TRUE;
} else { /* else: Inline command */
i = 0;
if (!Plain) {
if (!strcmp(AGArgU(0), "B")) {
WordSend();
Bold(stdout);
} else if (!strcmp(AGArgU(0), "UB")) {
WordSend();
BoldOff(stdout);
} else if (!strcmp(AGArgU(0), "I")) {
WordSend();
Italics(stdout);
} else if (!strcmp(AGArgU(0), "UI")) {
WordSend();
ItalicsOff(stdout);
} else if (!strcmp(AGArgU(0), "U")) {
WordSend();
Underline(stdout);
} else if (!strcmp(AGArgU(0), "UU")) {
WordSend();
UnderlineOff(stdout);
} else if (!strcmp(AGArgU(0), "FG")) {
static int Tmp;
WordSend();
if (!strcmp(AGArgU(1), "TEXT")) {
Tmp = 1;
} else if (!strcmp(AGArgU(1), "HIGHLIGHT")) {
Tmp = ColColor;
} else if (!strcmp(AGArgU(1), "BACKGROUND")) {
Tmp = 0;
} else {
Tmp = 1;
}
if (ColColor != 1) FGColor(stdout, Tmp);
else if (Tmp != 1 && ColReverse) Reverse(stdout);
else ReverseOff(stdout);
} else if (!strcmp(AGArgU(0), "BG")) {
static int Tmp;
WordSend();
if (!strcmp(AGArgU(1), "TEXT")) {
Tmp = 1;
} else if (!strcmp(AGArgU(1), "HIGHLIGHT")) {
Tmp = ColColor;
} else if (!strcmp(AGArgU(1), "BACKGROUND")) {
Tmp = 0;
} else {
Tmp = 0;
}
if (ColColor != 1) BGColor(stdout, Tmp);
else if (Tmp != 0 && ColReverse) Reverse(stdout);
else ReverseOff(stdout);
}
}
Command = TRUE;
}
} else { /* There was an @ but no command, so @ must be displayed */
ungetc(InC, InFile);
InC = '@';
}
}
if (!Command && InC != -1 && InsideNode) { /* If no command */
if (InC == '\\') InC = fgetc(InFile); /* '\' is the escape character */
if (InC == '\n' || InC == '\t' || InC == ' ') {
WordSend();
if (InC == '\n') PutEOL();
else if (InC == '\t') PutTab();
else PutSpace();
} else {
WordAddChar(InC);
}
}
LastNewLine = (InC == '\n');
Command = FALSE;
}
PutEnd();
NodeEnd();
if (!Plain) Normal(stdout);
}
#define MAX_WORD_LENGTH 80
static char Word[MAX_WORD_LENGTH+1];
static int WordLen = 0;
static void WordAddChar(char NewC) {
if (WordLen >= MAX_WORD_LENGTH) WordSend();
Word[WordLen++] = NewC;
}
static void WordSend(void) {
Word[WordLen] = '\000';
PutWord(Word);
WordLen = 0;
}
/***********************************\
* *
* Text displaying put-routines *
* *
\***********************************/
static FILE *PutFile=NULL;
static int PutPos, PutMaxColumn = 77;
static BOOL PutWrap;
static BOOL PutLastSpace;
static void PutInit(FILE *OutFile) {
PutFile = OutFile;
PutPos = 0;
PutWrap = FALSE;
PutLastSpace = FALSE;
}
static void PutWord(char *Str) {
static int Len;
if (PutFile) {
/* printf("PW: Len=%d, Str=%s\n", strlen(Str), Str);*/
Len = strlen(Str);
if (PutWrap) {
if (PutPos + Len >= PutMaxColumn) {
fprintf(PutFile, "\n%s", Str);
PutPos = Len - 1;
} else {
if (PutLastSpace) {
fputc(' ', PutFile);
PutPos++;
}
fprintf(PutFile, "%s", Str);
PutPos += Len;
}
} else {
PutPos += Len;
if (PutLastSpace) {
fputc(' ', PutFile);
PutPos++;
}
fprintf(PutFile, "%s", Str);
}
PutLastSpace = FALSE;
}
}
static void PutEOL(void) {
if (PutFile) {
fputc('\n', PutFile);
PutPos = 0;
PutLastSpace = FALSE;
}
}
static void PutTab(void) {
if (PutFile) {
PutPurgeSpace();
fputc('\t', PutFile);
PutPos = (PutPos + 8) & (~7);
}
}
static void PutSpace(void) {
if (PutFile) {
if (PutWrap) {
if (PutLastSpace) {
PutLastSpace = FALSE;
PutWord(" ");
}
PutLastSpace = TRUE;
} else {
PutWord(" ");
}
}
}
static void PutPurgeSpace(void) {
if (PutFile) {
if (PutLastSpace) {
if (PutPos + 1 >= PutMaxColumn) {
fputc('\n', PutFile);
PutPos = 0;
} else {
fputc(' ', PutFile);
PutPos++;
}
}
PutLastSpace = FALSE;
}
}
static void PutSetWidth(int Width) {
if (Width < 20) Width = 20;
PutMaxColumn = Width - 1;
}
static void PutSetWrap(void) {
PutWrap = TRUE;
}
static void PutEnd(void) {
PutFile = NULL;
}
struct NodeNode {
struct NodeNode *Left;
struct NodeNode *Right;
long Index;
char *Text;
};
/***********************************\
* *
* Node handling routines *
* *
\***********************************/
static int NodeAmount = -1;
static struct NodeNode *NodeNode=NULL;
/* The following function is only for internal use */
/* -> no prototype provided */
static struct NodeNode *AddNode(char *Str) {
static struct NodeNode *NewNode;
NewNode = malloc(sizeof(struct NodeNode) + strlen(Str) + 1);
if (NewNode) {
NewNode -> Left = NULL;
NewNode -> Right = NULL;
NewNode -> Index = ++NodeAmount;
NewNode -> Text = ((char *) NewNode) + sizeof(struct NodeNode);
strcpy(NewNode -> Text, Str);
} else {
fprintf(stderr," *** PANIC: Couldn't allocate memory!\n");
exit(EXIT_FAILURE);
}
return NewNode;
}
/* The following function is only for internal use */
/* -> no prototype provided */
static int FindNode(struct NodeNode *CurrNode, char *Str) {
int Tmp;
if (CurrNode == NULL) {
NodeNode = AddNode(Str);
return 1;
} else {
Tmp = strcmp(Str, CurrNode->Text);
if (Tmp < 0) {
if (CurrNode->Left) {
return FindNode(CurrNode->Left, Str);
} else {
CurrNode -> Left = AddNode(Str);
return CurrNode -> Left -> Index;
}
} else if (Tmp>0) {
if (CurrNode->Right) {
return FindNode(CurrNode->Right, Str);
} else {
CurrNode -> Right = AddNode(Str);
return CurrNode -> Right -> Index;
}
} else {
return CurrNode -> Index;
}
}
}
static int NodeNumber(char *Str) {
if (NodeAmount >= 0) return FindNode(NodeNode, Str);
return -1;
}
static void NodeInit(void) {
NodeEnd();
NodeAmount = 0;
}
/* The following function is only for internal use */
/* -> no prototype provided */
static void FreeNodes(struct NodeNode *CurrNode) {
if (CurrNode -> Left) FreeNodes(CurrNode->Left);
if (CurrNode -> Right) FreeNodes(CurrNode->Right);
free(CurrNode);
}
static void NodeEnd(void) {
if (NodeNode && NodeAmount >= 0) FreeNodes(NodeNode);
NodeNode = NULL;
NodeAmount = -1;
}
/***********************************\
* *
* AmigaGuide parsing routines *
* *
\***********************************/
#define AG_MAX_CHARS_PER_ARGUMENT 80
#define AG_MAX_ARGUMENTS_PER_COMMAND 4
static char AGOriginalArgument[AG_MAX_ARGUMENTS_PER_COMMAND][AG_MAX_CHARS_PER_ARGUMENT+1];
static char AGUppercaseArgument[AG_MAX_ARGUMENTS_PER_COMMAND][AG_MAX_CHARS_PER_ARGUMENT+1];
static int AGArguments;
static char AGNULL = '\000';
/*-----------------------------------------------------------------*\
| |
| AGParseCommand - read AmigaGuide command from a string or file |
| and parse it. |
| |
| Synopsis: |
| int Args = AGParseCommand(char *Command, NULL); |
| int Args = AGParseCommand(NULL, FILE *InFile); |
| |
| Function: |
| Reads an AmigaGuide command either from a string or a file and |
| parses it. AGParseCommand assumes that leading @ is not in the |
| string / has been read from the file. If the first character is |
| "{" the command is assumed to be an inline command, otherwise |
| it is assumed to be a full command line. |
| |
| Inputs: |
| char *Command - if not NULL, this is taken to be the Command |
| FILE *InFile - if not NULL, this is the file where the Command |
| will be read. |
| Command and InFile are mutually exclusive. |
| |
| Result: |
| Args - The amount of arguments read from the command |
| |
\*-----------------------------------------------------------------*/
static int AGParseCommand(char *Command, FILE *InFile) {
int CPos = -1, ArgPos = 0;
BOOL InQuotes = FALSE, GoQuotes = FALSE, CommandLine = FALSE, Quit = FALSE;
static int Curr;
AGArguments = 0;
Curr = fgetc(InFile);
if (Curr != '{') {
CommandLine = TRUE;
ungetc(Curr, InFile);
}
do {
if (!InFile) Curr = (unsigned char) Command[++CPos];
else Curr = fgetc(InFile);
if (!Curr || Curr == -1 || Curr == '\n' ||
!CommandLine && !InQuotes && Curr == '}') {
Curr = ' ';
Quit = TRUE;
}
if (Curr == '"') {
Curr = ' ';
if (!InQuotes) GoQuotes = TRUE;
else InQuotes = FALSE;
}
if(IsSpace(Curr) && ArgPos && !InQuotes) {
if (AGArguments <= AG_MAX_ARGUMENTS_PER_COMMAND) {
AGOriginalArgument[AGArguments-1][ArgPos] = '\000';
AGUppercaseArgument[AGArguments-1][ArgPos] = '\000';
}
ArgPos = 0;
} else {
if (ArgPos < AG_MAX_CHARS_PER_ARGUMENT && (!IsSpace(Curr) || InQuotes)) {
if (!ArgPos) AGArguments++;
if (AGArguments <= AG_MAX_ARGUMENTS_PER_COMMAND) {
AGOriginalArgument[AGArguments-1][ArgPos] = Curr;
AGUppercaseArgument[AGArguments-1][ArgPos] = ToUpper(Curr);
}
ArgPos++;
}
}
if (GoQuotes) {
InQuotes = TRUE;
GoQuotes = FALSE;
}
} while (!Quit);
if (AGArguments > AG_MAX_ARGUMENTS_PER_COMMAND)
AGArguments = AG_MAX_ARGUMENTS_PER_COMMAND;
return AGArguments;
}
/*-----------------------------------------------------------------*\
| |
| AGArgs - returns last AmigaGuide command argument count |
| |
| Synopsis: |
| int Args = AGArgs(); |
| |
| Function: |
| Returns argument count from last call of AGParseCommand() |
| |
| Inputs: |
| |
| Result: |
| Args - The amount of arguments read from the command |
| |
\*-----------------------------------------------------------------*/
static int AGArgs(void) {
return AGArguments;
}
/*-----------------------------------------------------------------*\
| |
| AGArg - returns desired argument from last AmigaGuide command |
| |
| Synopsis: |
| char *Arg = AGArg(int ArgNo); |
| |
| Function: |
| Returns desired argument from last call of AGParseCommand(). |
| |
| Inputs: |
| ArgNo - 0 .. AGArgs()-1 |
| |
| Result: |
| Arg - A pointer to the desired argument. If ArgNo was out of |
| range, a pointer to an empty string is returned. |
| |
\*-----------------------------------------------------------------*/
static char *AGArg(int Arg) {
if (Arg <= AG_MAX_ARGUMENTS_PER_COMMAND && Arg >= 0) return AGOriginalArgument[Arg];
else return &AGNULL;
}
/*-----------------------------------------------------------------*\
| |
| AGArg - returns desired argument from last AmigaGuide command |
| converted to uppercase. |
| |
| Synopsis: |
| char *Arg = AGArg(int ArgNo); |
| |
| Function: |
| Returns desired argument from last call of AGParseCommand() |
| converted to uppercase letters. |
| |
| Inputs: |
| ArgNo - 0 .. AGArgs()-1 |
| |
| Result: |
| Arg - A pointer to the desired argument. If ArgNo was out of |
| range, a pointer to an empty string is returned. |
| |
\*-----------------------------------------------------------------*/
static char *AGArgU(int Arg) {
if (Arg <= AG_MAX_ARGUMENTS_PER_COMMAND && Arg >= 0) return AGUppercaseArgument[Arg];
else return &AGNULL;
}